package controle;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;

import javax.swing.JComboBox;
import javax.swing.JLabel;

import java.io.OutputStream;

import client.Connect;
import client.FtpClient;

import comum.Client;
import comum.InfoArquivo;
import comum.Mensagem;
import comum.Pacote;
import comum.PacoteFile;

import vista.TelaCliente;

/**
 * Classe que faz a requisicao e o tratamento de respostas das solicitacoes para com o servidor
 * @author gbomfim
 *
 */
public class RequestManager {

	static TelaCliente tela = TelaCliente.getInstance();
	
	/**
	 * Metodo de carga inicial da lista de arquivos do diretorio default  da lista de extensoes do servidor.
	 * E chamado no inicio do programa cliente;
	 */
	public void initialUpdateList()
	{		
		Pacote pacote = new Pacote("list", tela.ABSOLUTEPATHSERVIDOR, "");
		pacote.sendTo(FtpClient.client.getIpServer(), FtpClient.client.getPortServer());
				
			String[] lines = pacote.getResponse().split("\\r?\\n", 3);
			Pacote pacoteResponse = new Pacote(lines[0].split("->")[1], lines[1].split("->")[1], lines[2]);
			tela.currentPathServidor = pacote.getPath();
			tela.ABSOLUTEPATHSERVIDOR = pacote.getPath();
			tela.listaArquivosServidor.setListData(this.trataContentList(pacoteResponse.getContent()).toArray());
		
	}
	
	/**
	 * Metodo de solicitacao da lista de arquivos do diretorio e da lista de extensoes do servidor.
	 * E chamada ao final de todos os mtodos que alteram o servidor e no botao de refresh
	 * Tambem popula a interface
	 */
	public void updateList()
	{
		Pacote pacote = new Pacote("list", tela.currentPathServidor, "");
		pacote.sendTo(FtpClient.client.getIpServer(), FtpClient.client.getPortServer());
				
			String[] lines = pacote.getResponse().split("\\r?\\n", 3);
			Pacote pacoteResponse = new Pacote(lines[0].split("->")[1], lines[1].split("->")[1], lines[2]);
			tela.listaArquivosServidor.setListData(this.trataContentList(pacoteResponse.getContent()).toArray());
		
	}
	
	/**
	 * Classe que passa para o servidor o path com o nome do arquivo que eu quero renomear e o novo nome do mesmo.
	 * Trato tambem o retorno para ver se deu tudo certo
	 * @param name
	 * @param newName
	 */
	public void renameFile(String name,String newName)
	{
		Pacote pacote = new Pacote("rename", tela.currentPathServidor+"/"+name, "newPath->"+tela.currentPathServidor+"/"+newName);
		pacote.sendTo(FtpClient.client.getIpServer(), FtpClient.client.getPortServer());
				
			String[] lines = pacote.getResponse().split("\\r?\\n", 3);
			Pacote pacoteResponse = new Pacote(lines[0].split("->")[1], lines[1].split("->")[1], lines[2]);
			this.updateList();
		
	}
	
	/**
	 * Trata a resposta da lista de arquivos do diretorio do servidor, ordenando e retornando a lista ja formatada 
	 * @param content
	 * @return ArrayList<String>
	 */
	public ArrayList<String> trataContentList(String content)
	{
		String[] lines = content.split("folders->");
		lines = lines[1].split("files->");
		
		String[] pastas = lines[0].split("\\r?\\n");
		
		String[] arquivos = lines[1].split("\\r?\\n");
		
		ArrayList<String> arrPastas = new ArrayList<>(Arrays.asList(pastas));
		tela.qtPastasServidor = arrPastas.size();
		ArrayList<String> arrArquivos = new ArrayList<>(Arrays.asList(arquivos));
		tela.arrArquivosServidor = arrArquivos;
		tela.qtArqServidor = arrArquivos.size();
		ArrayList<String> arrExt = this.getExtList(arrArquivos);
		
		tela.listExtServidor.removeAllItems();
		for (int i = 0; i < arrExt.size(); i++) {
			tela.listExtServidor.insertItemAt("."+arrExt.get(i), i);
		}
		tela.listExtServidor.setSelectedIndex(0);
			
		
		ArrayList<String> arrTotal = new ArrayList<String>();

		if (!tela.currentPathServidor.equals(tela.ABSOLUTEPATHSERVIDOR)) {
			arrTotal.add("...");
		}
		if (arrPastas.size() != 0) {
			arrTotal.addAll(arrPastas);
			arrTotal.add("---");
		}
		if (arrArquivos.size() != 0) {
			arrTotal.addAll(arrArquivos);
			arrTotal.add("---");
		}
		return arrTotal;
	}
	
	/**
	 * Trato a lista de arquivos recebida para retornar a lista de extensoes referentes a ela
	 * @param arrArquivos
	 * @return ArrayList<String> arrayExtensoes
	 */
	
	public ArrayList<String> getExtList(ArrayList<String> arrArquivos)
	{
		ArrayList<String> arrExt = new ArrayList<String>();
		for (String arquivo : arrArquivos) {
			int i = arquivo.lastIndexOf('.');
			String ext = null;
			if (i > 0 && i < arquivo.length() - 1)
				ext = arquivo.substring(i + 1).toLowerCase();

			if ((ext != null) && (ext !="") && (arrExt.indexOf(ext) == -1))
				arrExt.add(ext);
		}		
		return arrExt;
		
	}
	
	
	/**
	 * Faco a requisicao da edicao do arquivo, passando o path do arquivo e o path do arquivo temporario gerado enquanto a edicao e realizada.
	 * Recebo assim o arquivo a ser editado.
	 * @param socket
	 * @param path
	 * @param tempPath
	 */
	public void editRequestFile(Socket socket, String path, String tempPath) {
		try {
			String message = "type->edit\n";
			message += "path->"+path+"\n";
			message += "content->get\n";
			message += "end\n";
			
			OutputStream socketOutput = socket.getOutputStream();
			socketOutput.write(message.getBytes());
			
			PacoteFile.receiveFile(socket, tempPath);
			
			
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	/**
	 * Faco o envio do arquivo editado, para o path de origem , a partir do path temporario gerado
	 * @param socket
	 * @param path
	 * @param tempPath
	 */
	public void editSendFile(Socket socket, String path, String tempPath) {
		try {
			String message = "type->edit\n";
			message += "path->"+path+"\n";
			message += "content->send\n";
			message += "end\n";
			
			OutputStream socketOutput;
			socketOutput = socket.getOutputStream();
			
			socketOutput.write(message.getBytes());
			
			PacoteFile.sendFile(socket, tempPath);
			File a = new File(tempPath);
			a.delete();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	
	/**
	 * Faco a solicitacao de transfencia de um arquivo , do servidor para o cliente
	 * @param path
	 * @param pathto
	 */
	public void getFile(String path, String pathto) {
		try {
			String message = "type->view\n";
			message += "path->"+path+"\n";
			message += "content->\n";
			message += "end\n";
			
			Socket socket = new Socket(FtpClient.client.getIpServer(), FtpClient.client.getPortServer());
			OutputStream socketOutput = socket.getOutputStream();
			socketOutput.write(message.getBytes());
			
			PacoteFile.receiveFile(socket, pathto);
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	/**
	 * Faco a solicitacao das informacoes de um arquivo do referido path para o servidor
	 * Tambem atualizo a interface com esses dados.
	 * @param name
	 */
	@SuppressWarnings("deprecation")
	
	public void getInfo(String name)
	{
		Pacote pacote = new Pacote("getinfo", tela.currentPathServidor+"/"+name, "");
		pacote.sendTo(FtpClient.client.getIpServer(), FtpClient.client.getPortServer());
				
			String[] lines = pacote.getResponse().split("\\r?\\n", 3);
			Pacote pacoteResponse = new Pacote(lines[0].split("->")[1], lines[1].split("->")[1], lines[2]);
			
			lines = pacoteResponse.getContent().split("->");
		
			tela.sizeFileServidor.setText(lines[1].split("lastview")[0] + "  kb");
			tela.lastModServidor.setText(lines[3]);				
	}

	/**
	 * Faco o envio dos arquivos do cliente(parametro path) para o servidor(parametro pathto)
	 * @param path
	 * @param pathto
	 */
	public void sendFile(String path, String pathto) {
		try {
			String message = "type->write\n";
			message += "path->"+pathto+"\n";
			message += "content->\n";
			message += "end\n";
			
			Socket socket = new Socket(FtpClient.client.getIpServer(), FtpClient.client.getPortServer());
			OutputStream socketOutput = socket.getOutputStream();
			socketOutput.write(message.getBytes());
			
			//recebendo permissao de envio
			BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			String text = "", tmp = "";
			while( (tmp = reader.readLine()) != null ) {
				if(tmp.equals("end")) { break; }
				text += tmp+"\n";
			}
			
			System.out.println(text);
			
			PacoteFile.sendFile(socket, path);
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	/**
	 * Metodo de solicitacao de remocao do arquivo junto ao servidor a partir do path passado.
	 * @param path
	 */
	public void removeFile(String path) {
		Pacote pacote = new Pacote("remove", path, "");
		pacote.sendTo(FtpClient.client.getIpServer(), FtpClient.client.getPortServer());
				
		String[] lines = pacote.getResponse().split("\\r?\\n", 3);
		Pacote pacoteResponse = new Pacote(lines[0].split("->")[1], lines[1].split("->")[1], lines[2]);
		this.updateList();
	}

	/**
	 * Metodo de busca de dos arquivos a partir da extensao passada, e itero fazendo o envio um a um para o servidor. 
	 * @param extension
	 */
	public void sendManyFiles(String extension)
	{
		ArrayList<String> arquivosAseremEnviados = new ArrayList<String>();
		for (String arquivo : tela.arrArquivos) {
			if(getExtFromString(arquivo).equalsIgnoreCase(extension))
				arquivosAseremEnviados.add(arquivo);
		}
		for (String arquivo : arquivosAseremEnviados) {
			this.sendFile(tela.currentPathUsuario.concat("/"+arquivo), tela.currentPathServidor.concat("/"+arquivo));
		}
		this.updateList();
	}
	
	/**
	 * Metodo de busca de dos arquivos a partir da extensao passada, e itero fazendo a solicitacao de recibimento um a um junto ao servidor.
	 * @param extension
	 */
	public void getManyFiles(String extension)
	{
		ArrayList<String> arquivosAseremEnviados = new ArrayList<String>();
		for (String arquivo : tela.arrArquivosServidor) {
			if(getExtFromString(arquivo).equalsIgnoreCase(extension))
				arquivosAseremEnviados.add(arquivo);
		}
		for (String arquivo : arquivosAseremEnviados) {
			this.getFile(tela.currentPathServidor.concat("/"+arquivo), tela.currentPathUsuario.concat("/"+arquivo));
		}
		try {
			tela.montaLista(tela.currentPathUsuario);
		} catch (IOException e) {
			System.out.println("Erro ao atualizar a lista de arquivos do user");
		}
	}
	
	private String getExtFromString(String file)
	{
		int i = file.lastIndexOf('.');
		String ext = null;
		if (i > 0 && i < file.length() - 1)
			ext = file.substring(i + 1).toLowerCase();
		return "."+ext;
	}		
}

